﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace SharedGamesClasses {

    public static class CrazyEights {


        public const int NUM_OF_PLAYERS = 2;
        public const int USER = 0;
        public const int COMPUTER = 1;
        public static int suppend = 0;
        private const string COMPUTERS_NAME = "Computer";
        private const string PICK = "Pick one of your card <or enter S to sort your card>: ";
        private const string NO_CARD = "You have no cards that can play. Taking one from the draw pile";
        private const string WRONG_CARD = "Invalid card code";
        private const string PICK_NO_CARD = "You don't have that card";
        private const string CANNOT_PLAY = "Can't play that card now";
        private const string DISPLAY_CARD_ON_TOP = "The card on top of the discard pile is now ";
        private const string COMPUTER_WIN = "***** Computer has won. *****";
        private const string USER_WIN = "***** You won. *****";
        private const string ANOTHER_GAME = "Another game? <y or n>";
        private const int NUM_OF_STARTING_CARDS = 8;

        // More constants and/or class variables may be needed.

        private static CardPile drawPile;     // The pile of cards that the players can draw from.
        private static CardPile discardPile;  // The pile of cards discarded by the players.
        private static Card Pick;
        private static Hand[] hands = new Hand[NUM_OF_PLAYERS];
        private static bool isUserTurn;
        private static Suit currentSuit;
        private static bool gameInPlay;

        /// <summary>
        /// Set up to play the game, 
        /// by shuffling the drawPile of cards 
        /// and then dealing the two hands.
        /// </summary>
        public static void SetUpGame() {
            drawPile = new CardPile(true);
            drawPile.Shuffle();
            hands[USER] = new Hand(drawPile.DealCards(NUM_OF_STARTING_CARDS));
            hands[COMPUTER] = new Hand(drawPile.DealCards(NUM_OF_STARTING_CARDS));
            SetUpTheDiscardPile();
            isUserTurn = true;
            hands[USER].Sort();
            gameInPlay = true;
            Pick = drawPile.DealOneCard();
            discardPile.Add(Pick);
            SetCurrentSuit(Pick.GetSuit());
        } //end SetUpGame

        private static void SetUpTheDiscardPile() {
            discardPile = new CardPile();
            // More code needed here.
        }

        public static void PlayConsole()
        {
            string pickCard;
            SetUpGame();
            Console.WriteLine(DISPLAY_CARD_ON_TOP + Pick.ToString(true, true));
            while (gameInPlay == true)
            {
                if (isUserTurn) // user turn
                {
                    
                    Console.Out.WriteLine("Your turn.");
                    DisplayHand(USER);

                    if (IsUserHaveCard() == false) //user have valid card
                    {
                        while (IsUserHaveCard() == false && hands[USER].GetCount() < 13)
                        {
                            Console.WriteLine(NO_CARD);
                            if (drawPile.GetCount() == 0)
                            {
                                ExchangPile();
                            }
                            Card addCard = drawPile.DealOneCard();
                            hands[USER].Add(addCard);
                            DisplayHand(USER);
                        }
                        if (IsUserHaveCard() == false)
                        {
                            isUserTurn = false;
                        }

                    }
                    if (IsUserHaveCard() == true)
                    {
                        Console.WriteLine();
                        Console.Out.Write(PICK);
                        pickCard = Console.In.ReadLine();
                        Card yourpick = Card.TryToCreateCard(pickCard);
                        while (CheckValue(pickCard) != 1)
                        {
                            if (CheckValue(pickCard) == -1)
                                Console.WriteLine(WRONG_CARD);
                            else if (CheckValue(pickCard) == -2)
                            {
                                Console.WriteLine(PICK_NO_CARD);
                            }
                            else
                            {
                                Console.WriteLine(CANNOT_PLAY);
                            }
                            Console.WriteLine(PICK_NO_CARD);
                            Console.WriteLine(PICK);
                   
                            pickCard = Console.In.ReadLine();
                            yourpick = Card.TryToCreateCard(pickCard);
                        }
                        Pick = yourpick;
                        SetCurrentSuit(Pick.GetSuit());
                        discardPile.Add(Pick);
                        hands[USER].Remove(yourpick);
                        
                        if (CheckWinter(USER) == true) //check user win
                        {
                            Console.WriteLine(USER_WIN);
                            Console.WriteLine(ANOTHER_GAME);
                            char cplayAgain = Char.Parse(Console.ReadLine());
                            if (cplayAgain == 'y') // play again
                            {
                                SetUpGame();
                            }
                            else
                            {
                                gameInPlay = false;
                            }

                        }
                        Console.Out.WriteLine(DISPLAY_CARD_ON_TOP + Pick.ToString(true, true));
                        isUserTurn = false;


                    }
                }
                else // computer turn
                {
                    Console.Out.WriteLine("Computer Turn");
                    DisplayHand(COMPUTER);
                    Card computerPick = ComputerThrowCards();
                    if (computerPick == null)
                    {
                        Card throwCard = ComputerThrowCards();
                        while (throwCard == null && hands[COMPUTER].GetCount() < 13)
                        {
                            Console.WriteLine(NO_CARD);
                            if (drawPile.GetCount() == 0)
                            {
                                ExchangPile();
                            }
                            Card addCard = drawPile.DealOneCard();
                            hands[COMPUTER].Add(addCard);
                            computerPick = ComputerThrowCards();
                            DisplayHand(COMPUTER);
                            throwCard = ComputerThrowCards();
                        }
                        if (ComputerThrowCards() == null)
                        {
                            isUserTurn = true;
                        }
                        else
                        {
                            Pick = computerPick;
                            SetCurrentSuit(Pick.GetSuit());
                            discardPile.Add(Pick);
                            hands[COMPUTER].Remove(Pick);
                            isUserTurn = true;
                            Console.Out.WriteLine(DISPLAY_CARD_ON_TOP + Pick.ToString(true, true));
                        }
                    }
                    else
                    {
                        Pick = computerPick;
                        SetCurrentSuit(Pick.GetSuit());
                        discardPile.Add(Pick);
                        hands[COMPUTER].Remove(Pick);
                        isUserTurn = true;
                        if (CheckWinter(COMPUTER) == true)
                        {
                            Console.WriteLine(COMPUTER_WIN);
                            Console.WriteLine(ANOTHER_GAME);
                            char cplayAgain = Char.Parse(Console.ReadLine());
                            if (cplayAgain == 'y') // play again
                            {
                                SetUpGame();
                            }
                            else
                            {
                                gameInPlay = false;
                            }
                        }
                        else
                            Console.Out.WriteLine(DISPLAY_CARD_ON_TOP + Pick.ToString(true, true));
                    }
                }
            }
        }
                // Play Crazy Eights until the user decides to stop.
            // end gameloop

         //end playconsole class
        public static bool CheckWinter(int index)
        {
            if (hands[index].GetCount() == 0)
                return true;
            return false;
        }
        public static void ExchangPile()
        {
            for (int i = 0; i < discardPile.GetCount(); i++)
            {
                Card temp = discardPile.DealOneCard();
                drawPile.Add(temp);
            }
        }
        public static int CheckValue(string pickCard)
        {
            Card yourpick = Card.TryToCreateCard(pickCard);
            if (yourpick == null)
                return -1;
            else if (hands[USER].Contains(yourpick) == false)
                return -2;
            else if (discardPile.GetCount() == 0)
                return 1;
            else if (yourpick.GetFaceValue() == FaceValue.Eight)
                return 1;
            else if (yourpick.GetFaceValue() != Pick.GetFaceValue() && yourpick.GetSuit() != Pick.GetSuit())
                return -3;
            else
                return 1;
        }
        /// <summary>
        /// Output the hand of cards of either the User or the Dealer
        /// Pre: hands initialised
        /// Post: Displays the hand of cards held by the specified player.
        /// </summary>
        public static void DisplayHand(int player) {
            string temp;
            if (player == USER)
            {
                temp = "You have ";
            }
            else
                temp = "Computer have ";
            Trace.Write(temp);
            hands[player].DisplayHand(true, true);
            //Trace.WriteLine;
         } // end DisplayHand

        public static bool IsUserHaveCard()
        {

            for (int i = 0; i < hands[USER].GetCount(); i++)
            {
                if ((hands[USER].GetCard(i).GetFaceValue() == Pick.GetFaceValue()) || hands[USER].GetCard(i).GetSuit() == currentSuit 
                    || hands[USER].GetCard(i).GetFaceValue() == FaceValue.Eight)
                    return true;
            }
            return false;
        }
        public static Card ComputerThrowCards()
        {
            List<Card> listSameSuit = new List<Card>();
            List<Card> listSameFaceValue = new List<Card>();
            List<Card> listEight = new List<Card>();
           
            
            for (int i = 0; i < hands[COMPUTER].GetCount(); i++)
            {
                if (hands[COMPUTER].GetCard(i).GetFaceValue() == FaceValue.Eight)
                    listEight.Add(hands[COMPUTER].GetCard(i));
                else if(hands[COMPUTER].GetCard(i).GetFaceValue() == Pick.GetFaceValue())
                    listSameFaceValue.Add(hands[COMPUTER].GetCard(i));
                else if(hands[COMPUTER].GetCard(i).GetSuit() == currentSuit)
                    listSameSuit.Add(hands[COMPUTER].GetCard(i));
            }
            if (listSameFaceValue.Count > 0)
            {
                return listSameFaceValue[0];
            }
            else if (listSameSuit.Count > 0)
                return listSameSuit[0];
            else if (listEight.Count > 0)
                return listEight[0];
            return null;
        }
        /// <summary>
        /// Lets the GUI or Console game set the current Suit.
        /// </summary>
        public static void SetCurrentSuit(Suit newSuit) {
            currentSuit = newSuit;
        }
        public static void Deal()
        {
            SetUpGame();
            DisplayHand(USER);
            DisplayHand(COMPUTER);
        }
        public static void ComputerDrawCard()
        {
                Trace.WriteLine("Computer Turn");
                DisplayHand(COMPUTER);
                Card computerPick = ComputerThrowCards();
                    if (computerPick == null)
                    {
                        Card throwCard = ComputerThrowCards();
                        while (throwCard == null && hands[COMPUTER].GetCount() < 13)
                        {
                            Console.WriteLine(NO_CARD);
                            if (drawPile.GetCount() == 0)
                            {
                                ExchangPile();
                            }
                            Card addCard = drawPile.DealOneCard();
                            hands[COMPUTER].Add(addCard);
                            computerPick = ComputerThrowCards();
                            DisplayHand(COMPUTER);
                            throwCard = ComputerThrowCards();
                        }
                        if (ComputerThrowCards() == null)
                        {
                            return;
                        }
                        
                            Pick = computerPick;
                            SetCurrentSuit(Pick.GetSuit());
                            discardPile.Add(Pick);
                            hands[COMPUTER].Remove(Pick);
                            isUserTurn = true;
                            Trace.WriteLine(DISPLAY_CARD_ON_TOP + Pick.ToString(true, true));
                        
                    }
                    
                        Pick = computerPick;
                        SetCurrentSuit(Pick.GetSuit());
                        discardPile.Add(Pick);
                        hands[COMPUTER].Remove(Pick);
                        isUserTurn = true;
                        if (CheckWinter(COMPUTER) == true)
                        {
                            Trace.WriteLine(COMPUTER_WIN);
                            Trace.WriteLine(ANOTHER_GAME);
                            char cplayAgain = Char.Parse(Console.ReadLine());
                            if (cplayAgain == 'y') // play again
                            {
                                SetUpGame();
                            }
                            else
                            {
                                gameInPlay = false;
                            }
                        }
                        else
                            Trace.WriteLine(DISPLAY_CARD_ON_TOP + Pick.ToString(true, true));
                    
        }
        public static int DrawACard(Card card)
        {
            int ret; 
            if(card.GetFaceValue() == FaceValue.Eight)
            {
                hands[USER].Remove(card);
                discardPile.Add(card);
                
                ret = 1;
                return ret;
            }
            if (card.GetFaceValue() != GetTopCardOnDiscardPile().GetFaceValue() && card.GetSuit() != currentSuit)
            {

                ret = -1;
            }
            else
            {
                SetCurrentSuit(card.GetSuit());
                hands[USER].Remove(card);
                discardPile.Add(card);
                ret = 0;
            }
              return ret;
        }

        /* The following methods are intended to be called by your GUI code.
         * I.e. you shouldn't need them when writing your Console game,
         * but do not delete them. */

        /// <summary>
        /// Helps the GUI to display what is in a player's hand.
        /// </summary>
        /// <returns>the Hand of the specified player</returns>
        public static Hand GetHand(int player) {
            return hands[player];
        }

        /// <summary>
        /// Helps the GUI to sort a player's hand.
        /// </summary>
        /// <returns>the Hand of the specified player</returns>
        public static void SortHand(int player) {
            // Add code here to sort the hand of the user. Hint: needs only one line.
            hands[player].Sort();
        }

        /// <summary>
        /// Helps the GUI to display what is on the top of the discard pile.
        /// </summary>
        /// <returns>the card on the top of the discard pile.</returns>
        public static Card GetTopCardOnDiscardPile() {
            return discardPile.GetLastCardInPile();
        }

        /// <summary>
        /// Tells the GUI whether there are any cards left in the draw pile.
        /// </summary>
        /// <returns>True, if there is at least one card in the draw pile. False, otherwise. </returns>
        public static bool DrawPileHasCards() {
            return (drawPile.GetCount() > 0);
        }


    } //end class CrazyEights
} //end namespace
